package com.jindianjichi.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import com.jindianjichi.basic.entity.SubjectCategory;
import com.jindianjichi.basic.entity.SubjectLabel;
import com.jindianjichi.basic.entity.SubjectMapping;
import com.jindianjichi.basic.service.SubjectCategoryService;
import com.jindianjichi.basic.service.SubjectLabelService;
import com.jindianjichi.basic.service.SubjectMappingService;
import com.jindianjichi.subject.common.enums.IsDeletedEnum;
import com.jindianjichi.subject.domain.convert.SubjectCategoryConverter;
import com.jindianjichi.subject.domain.convert.SubjectLabelConvert;
import com.jindianjichi.subject.domain.entity.SubjectCategoryBo;
import com.jindianjichi.subject.domain.entity.SubjectLabelBo;
import com.jindianjichi.subject.domain.service.SubjectCategoryDomainService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import static com.alibaba.fastjson.JSON.parseArray;

@Service
@Slf4j
public class subjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {
    @Resource
    private SubjectCategoryService subjectCategoryService;
    @Resource
    private SubjectMappingService subjectMappingService;
    @Resource
    private SubjectLabelService subjectLabelService;
    @Resource
    private ThreadPoolExecutor labelPoolExecutor;

    private Cache<String, String> localCache = CacheBuilder.newBuilder()
            .maximumSize(5000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();
    @Override
    public void addCategory(SubjectCategoryBo subjectCategoryBo) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.instance.convertToBoCategory(subjectCategoryBo);
        subjectCategory.setIsDeleted(IsDeletedEnum.UN_DELETED.getCode());
        subjectCategoryService.insert(subjectCategory);

    }
        @Override
    public List<SubjectCategoryBo> queryPrimaryCategory(SubjectCategoryBo subjectCategoryBo) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.instance.convertToBoCategory(subjectCategoryBo);
        log.info("subjectCategoryDomainServiceImpl.subjectCategory:{}", subjectCategory);
        if (subjectCategory.getCategoryType()==null){
            throw new RuntimeException("请选择分类类型");
        }
        List<SubjectCategory> list = subjectCategoryService.queryAllByLimit(subjectCategory);

        List<SubjectCategoryBo> subjectCategoryBoList = SubjectCategoryConverter.instance.convertBoToCategory(list);
        subjectCategoryBoList.forEach(bo-> {
           Integer subjectCount= subjectCategoryService.querySubjectCount(bo.getId());
           bo.setCount(subjectCount);
        });
        return subjectCategoryBoList;
    }
//逻辑删除分类数据
    @Override
    public int deleteCategory(SubjectCategoryBo subjectCategoryBo) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.instance.convertToBoCategory(subjectCategoryBo);
        log.info("subjectCategoryDomainServiceImpl.subjectCategory:{}", subjectCategory);
        subjectCategory.setIsDeleted(IsDeletedEnum.DELETED.getCode());
        if (subjectCategory.getId()==null){
            throw new RuntimeException("请选择需要删除的分类");
        }
        Integer deletedNum = subjectCategoryService.deleteCategory(subjectCategory);
        return deletedNum;
    }
//更新分类
    @Override
    public Boolean updateCategory(SubjectCategoryBo subjectCategoryBo) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.instance.convertToBoCategory(subjectCategoryBo);
        log.info("subjectCategoryDomainServiceImpl.subjectCategory:{}", subjectCategory);
        if (subjectCategory.getId()==null){
            throw new RuntimeException("请选择需要更新的分类");
        }
        Integer updateNum = subjectCategoryService.deleteCategory(subjectCategory);
        Boolean ifUpate=updateNum>0 ;

       return ifUpate;
    }

    public List<SubjectCategoryBo> queryCategory(SubjectCategoryBo subjectCategoryBo) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.instance.convertToBoCategory(subjectCategoryBo);
        log.info("subjectCategoryDomainServiceImpl.subjectCategory:{}", subjectCategory);
        SubjectCategory subCategory = SubjectCategoryConverter.instance.convertToBoCategory(subjectCategoryBo);
        List<SubjectCategory> subList = subjectCategoryService.queryAllByLimit(subCategory);
        List<SubjectCategoryBo> subCategoryList = SubjectCategoryConverter.instance.convertBoToCategory(subList);
        return subCategoryList;

    }

    /**
     * 查询分类及标签
     * @param subjectCategoryBo
     * @return
     */
    @SneakyThrows
    @Override
    public List<SubjectCategoryBo> queryCategoryAndLabel(SubjectCategoryBo subjectCategoryBo) {
        String cacheKey = "queryCategoryAndLabel." + subjectCategoryBo.getId();
        String content = localCache.getIfPresent(cacheKey);
        List<SubjectCategoryBo>list=new LinkedList<>();
        if (StringUtils.isBlank(content)){
         list =  getSubjectCategoryBos(subjectCategoryBo.getId());
            localCache.put(cacheKey,JSON.toJSONString(list));
        }else {
            list=parseArray(content,SubjectCategoryBo.class);
        }

        return list;
    }

    private List<SubjectCategoryBo> getSubjectCategoryBos(Long categoryId) {
        //查询当前大分类下的小分类
        SubjectCategory subjectCategory=new SubjectCategory();
        subjectCategory.setParentId(categoryId);
        subjectCategory.setIsDeleted(IsDeletedEnum.UN_DELETED.getCode());
        List<SubjectCategory> categoryList = subjectCategoryService.queryAllByLimit(subjectCategory);
        if(log.isInfoEnabled()){
            log.info("查询当前大分类下的小分类:{}", JSON.toJSONString(categoryList));
        }
        List<SubjectCategoryBo> subjectCategoryBoList=  SubjectCategoryConverter.instance.convertBoToCategory(categoryList);
        //一次获取标签信息
        List<FutureTask<Map<Long,List<SubjectLabelBo>>>> futureTaskList=new ArrayList<>();
        //线程池并发调用
        Map<Long,List<SubjectLabelBo>> map= Maps.newHashMap();
////        FutureTask实现
//        subjectCategoryBoList.forEach(categoryBo->{
//            FutureTask<Map<Long, List<SubjectLabelBo>>> futureTask = new FutureTask<>(()->
//                getSubjectLabelBoList(categoryBo));
//            futureTaskList.add(futureTask);
//            labelPoolExecutor.submit((Runnable) futureTask);
//        });
//        for (FutureTask<Map<Long, List<SubjectLabelBo>>> futureTask : futureTaskList) {
//            Map<Long, List<SubjectLabelBo>> resultMap = futureTask.get();
//            if (CollectionUtils.isEmpty(resultMap)){
//                continue;
//            }
//            map.putAll(resultMap);
//        }
//        subjectCategoryBoList.forEach(categoryBo->{
//          categoryBo.setLabelBoList(map.get(categoryBo.getId()));
//        });
        //2.CompletableFuture实现
        List<CompletableFuture<Map<Long, List<SubjectLabelBo>>>> completableFutureList = subjectCategoryBoList.stream().map(categoryBo ->
                CompletableFuture.supplyAsync(() -> getSubjectLabelBoList(categoryBo), labelPoolExecutor)
        ).collect(Collectors.toList());
        completableFutureList.forEach(future -> {
            try {
                Map<Long, List<SubjectLabelBo>> resultMap = future.get();
                map.putAll(resultMap);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        });
        subjectCategoryBoList.forEach(categoryBo->{
          categoryBo.setLabelBoList(map.get(categoryBo.getId()));
        });
        return subjectCategoryBoList;
    }

    private Map<Long,List<SubjectLabelBo>> getSubjectLabelBoList(SubjectCategoryBo categoryBo) {
        Map<Long,List<SubjectLabelBo>> labelMap=new HashMap<>();
        SubjectMapping subjectMapping=new SubjectMapping();
        subjectMapping.setCategoryId(categoryBo.getId());
        List<SubjectMapping> mappingList = subjectMappingService.queryByLabelId(subjectMapping);
        List<Long> labelIds = mappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
        List<SubjectLabel>labelList= subjectLabelService.batchQueryById(labelIds);
        List<SubjectLabelBo> labelBoList = SubjectLabelConvert.instance.convertBoList(labelList);
        labelMap.put(categoryBo.getId(),labelBoList);
        return labelMap;
    }
}

